home *** CD-ROM | disk | FTP | other *** search
- /* Internet LPD Server filters
- * written by David Johnson (dave@cs.olemiss.edu)
- *
- * This code is in the public domain.
- *
- * Revision History:
- *
- * Revision 1.4 91/09/25 dave
- * Changed subtraction of integer 1 to character '1' in wait_for_printer()
- *
- * Revision 1.3 91/09/19 dave
- * Handle output processing for expanding tabs
- *
- * Revision 1.2 91/09/17 dave
- * Handle output processing for each device, not just internal
- *
- * Revision 1.1 91/09/14 dave (from marko winblad)
- * Correction to definition of variable 'c' in input_char() to int.
- *
- * Revision 1.0 91/09/04 dave
- * Initial Release
- *
- */
- #include <stdio.h>
- #include <fcntl.h>
- #include <ctype.h>
- #include <string.h>
- #include <time.h>
- #include <sys/stat.h>
- #include <dos.h>
- #ifdef __TURBOC__
- #include <io.h>
- #include <dir.h>
- #endif
- #include "global.h"
- #include "mbuf.h"
- #include "proc.h"
- #include "iface.h"
- #include "asy.h"
- #include "socket.h"
- #include "dirutil.h"
- #include "commands.h"
- #include "files.h"
- #include "lp.h"
- #include "lpd.h"
- #include "lpdfilt.h"
-
- /*
- * All filters which are supported are prototyped in lpdfilt.h
- */
-
- /* local functions - public */
- void output_char __ARGS((struct filter_stream *io_stream, int c));
- void output_string __ARGS((struct filter_stream *io_stream, char *s));
- void stream_flush __ARGS((struct filter_stream *io_stream));
-
- /* local functions - private */
- static void stream_setup __ARGS((struct filter_stream *io_stream));
- static int input_char __ARGS((struct filter_stream *io_stream));
-
-
-
- struct LPDfilter filter_list[] = {
- {"text", text_filter}, /* generic IF filter */
-
- {"ps_switch", ps_switch_filter}, /* postscript or */
- /* text auto-switch */
-
- {"text_ps", text_ps_filter}, /* postscript or */
- /* text to postscript */
- { NULL, NULLVFP}
- };
-
- /*
- * Wait for printer to be available.
- * Only called for DOS devices (LPT1-3, COM1-4).
- */
- static int
- wait_for_printer( device )
- struct LPDdevice *device;
- {
- union REGS regs;
-
- #define NOT_BUSY 0x80
- #define ACK 0x40
- #define OUT_OF_PAPER 0x20
- #define SELECTED 0x10
- #define IO_ERROR 0x08
-
- if( *device->name == 'L' ) { /* LPT? */
-
- for(;;) {
- regs.h.ah = 2; /* READ STATUS */
- regs.x.dx = *(device->name + 3) - '1'; /* 0-2 */
- int86( 0x17, ®s, ®s );
- if( (regs.h.ah & (NOT_BUSY|SELECTED))
- == (NOT_BUSY|SELECTED) )
- break;
- YIELD;
- }
-
- } else if( *device->name == 'C' ) { /* COM? */
-
- /* This needs more work...what are the status values
- * returned?
- */
- for(;;) {
- regs.h.ah = 3; /* READ STATUS */
- regs.x.dx = *(device->name + 3) - '1'; /* 0-3 */
- int86( 0x14, ®s, ®s );
- if( (regs.h.ah & 0x60) != 0 )
- break;
- YIELD;
- }
- }
- }
-
- /*
- * Filter "stream" I/O routines.
- */
- static void
- stream_setup( io_stream )
- struct filter_stream *io_stream;
- {
- if( io_stream->type == IO_SOCKET ) {
- sockmode( io_stream->stream.socket, SOCK_ASCII );
- sockowner( io_stream->stream.socket, Curproc );
- }
- }
-
- void
- output_char( io_stream, c )
- struct filter_stream *io_stream;
- int c;
- {
- struct mbuf *bp;
-
- switch( io_stream->type ) {
- case IO_SOCKET:
- usputc( io_stream->stream.socket, c );
- break;
- case IO_FILE:
- wait_for_printer( io_stream->device );
- putc( c, io_stream->stream.fp );
- break;
- case IO_LOCAL:
- bp = pushdown(NULLBUF, 1);
- bp->data[0] = c;
- asy_send( (io_stream->stream.ifp)->dev, bp );
- (io_stream->stream.ifp)->lastsent = secclock();
- break;
- }
- }
-
- static int
- input_char( io_stream )
- struct filter_stream *io_stream;
- {
- int c;
-
- switch( io_stream->type ) {
- case IO_SOCKET:
- c = recvchar( io_stream->stream.socket );
- break;
- case IO_FILE:
- c = getc( io_stream->stream.fp );
- break;
- case IO_LOCAL:
- c = get_asy((io_stream->stream.ifp)->dev);
- break;
- }
- return c;
- }
-
- void
- output_string( io_stream, s )
- struct filter_stream *io_stream;
- char *s;
- {
- struct mbuf *bp;
-
- switch( io_stream->type ) {
- case IO_SOCKET:
- usputs( io_stream->stream.socket, s );
- break;
- case IO_FILE:
- wait_for_printer( io_stream->device );
- fputs( s, io_stream->stream.fp );
- break;
- case IO_LOCAL:
- bp = pushdown(NULLBUF, strlen(s));
- strcpy( bp->data, s );
- asy_send( (io_stream->stream.ifp)->dev, bp );
- (io_stream->stream.ifp)->lastsent = secclock();
- break;
- }
- }
-
- void
- stream_flush( io_stream )
- struct filter_stream *io_stream;
- {
- if( io_stream->type == IO_FILE )
- fflush( io_stream->stream.fp );
- else if( io_stream->type == IO_SOCKET )
- usflush( io_stream->stream.socket );
- }
-
-
- /*
- * Write accounting information to accounting file
- * Adapted from PLP
- */
- static void
- write_to_af( parms, pages )
- struct filter_parms *parms;
- int pages;
- {
- time_t current_time;
- FILE *fp;
-
- (void)time( ¤t_time );
-
- if( parms->af_file && access( parms->af_file, 02 ) >= 0 ) {
-
- if( (fp = fopen( parms->af_file, "a" )) != NULL ) {
- fprintf( fp, "%s\t%s\t%s\t%7d\t%c\t%s",
- parms->login_name ? parms->login_name : "NULL",
- parms->host ? parms->host : "NULL",
- parms->printer_name ? parms->printer_name : "NULL",
- pages,
- parms->format,
- ctime( ¤t_time ) );
- fclose( fp );
- }
- }
- YIELD;
- }
-
- /*
- * FILTER RULES:
- * All filters which do no network I/O must give up processing after
- * short intervals of printing using YIELD. NOS does not implement
- * pre-emptive scheduling and therefore other network activity will
- * be paused while printing.
- */
-
-
- /*
- * Standard text filter.
- */
- void
- text_filter( unused, vparms, unused2 )
- int unused;
- void *vparms;
- void *unused2;
- {
- struct filter_parms *parms;
- int c, i, x;
- int nchars = 0, nlines = 0, npages;
- char *indent_string;
-
- parms = (struct filter_parms *)vparms;
- npages = parms->pages; /* count banner page */
-
- #ifdef LPD_DEBUG
- tprintf( "text_filter( %p, %p, %c )\n", parms, parms->sync, parms->format );
- tprintf( "input = %d, output = %d\n", parms->input.type, parms->output.type );
- tflush();
- #endif
-
- if( parms->indent ) {
-
- /* build indent string */
- indent_string = malloc( parms->indent+1 );
- for( i = 0; i < parms->indent; i++ )
- indent_string[i] = ' ';
- indent_string[i] = NULL;
-
- /* indent first line */
- output_string( &parms->output, indent_string );
- }
-
- for( ;; ) {
- c = input_char( &parms->input );
-
- if( c == EOF ) {
- break;
- } else if( parms->literal ) {
- output_char( &parms->output, c );
- if( ++nchars > 128 ) {
- nchars = 0;
- YIELD;
- }
- } else if( c == '\n' || c == '\r' ) {
- if( c == '\n' && (parms->output.device->flags & CRMOD ) )
- output_char( &parms->output, '\r' );
- nchars = 0;
- output_char( &parms->output, c );
- if( ++nlines > parms->length ) {
- nlines = 0;
- npages++;
- }
- if( parms->indent )
- output_string( &parms->output, indent_string );
- YIELD;
- } else if( c == '\f' ) {
- nchars = 0;
- nlines = 0;
- npages++;
- output_char( &parms->output, c );
- if( parms->indent )
- output_string( &parms->output, indent_string );
- YIELD;
- } else if( c == '\b' ) {
- if( --nchars < 0 )
- nchars = 0;
- output_char( &parms->output, c );
- } else if( c == '\t' ) {
- if( parms->output.device->flags & XTABS ) {
- x = 8 - ((nchars + 8) % 8);
- if( nchars + x < parms->width )
- while( x-- > 0 )
- output_char( &parms->output, ' ' );
- }
- } else if( ++nchars < parms->width )
- output_char( &parms->output, c );
- }
- if( !parms->literal ) {
- if( nchars > 0 ) {
- output_char( &parms->output, '\r' );
- output_char( &parms->output, '\n' );
- nlines++;
- }
- if( nlines > 0 ) {
- output_char( &parms->output, '\f' );
- npages++;
- }
- }
- stream_flush( &parms->output );
- YIELD;
-
- if( parms->indent )
- free( indent_string );
-
- write_to_af( parms, npages );
-
- if( parms->sync ) /* TRUE if not called from ps_text */
- psignal( parms->sync, 0 );
- }
-
-
- /*
- * encapsulated-postscript/regular text auto-switch filter.
- *
- * If file starts with '%!' the file must be PostScript.
- * Use the ps_start, ps_end, and default_ps parameters as appropriate to
- * place the printer in the correct mode.
- *
- * Otherwise, send the file through the default text_filter.
- *
- * BUGS: must be fed a file, if fed a stream, the first two characters
- * of a non-PostScript stream will be lost.
- */
- void
- ps_switch_filter( unused, vparms, unused2 )
- int unused;
- void *vparms;
- void *unused2;
- {
- struct filter_parms *parms;
- int c;
- int *sync, postscript;
- char *start, *end;
-
- parms = (struct filter_parms *)vparms;
-
- #ifdef LPD_DEBUG
- tprintf( "ps_switch_filter( %c )\n", parms->format );
- tflush();
- #endif
-
- postscript = 0;
- start = end = NULL;
-
- if( parms->format != 'p' ) {
- /*
- * See if file is encapsulated-postscript
- */
- c = input_char( &parms->input );
- if( c == '%' ) { /* maybe */
- c = input_char( &parms->input );
- if( c == '!' ) { /* YES! */
- postscript = 1;
-
- if( !parms->default_ps ) {
- start = parms->ps_start;
- end = parms->ps_end;
- }
- }
- }
- rewind( parms->input.stream.fp );
- }
-
- YIELD;
- if( !postscript ) {
- if( parms->default_ps ) {
- start = parms->ps_end;
- end = parms->ps_start;
- }
- }
- /*
- * Place the printer in Standard Text or PostScript mode as
- * appropriate.
- */
- if( start )
- output_string( &parms->output, start );
- /*
- * save sync address so that text_filter will not signal our
- * parent since output may not be complete.
- */
- sync = parms->sync;
- parms->sync = 0;
-
- /*
- * call the standard text_filter.
- */
- if( postscript ) /* PostScript files must be literal */
- parms->literal = 1;
- text_filter( unused, vparms, unused2 );
- YIELD;
-
- /*
- * Place the printer back into the default mode.
- */
- if( end )
- output_string( &parms->output, end );
- /*
- * signal our parent
- */
- psignal( sync, 0 );
- }
-
-
- /*
- * encapsulated-postscript/regular text to postscript filter.
- *
- * If file starts with '%!' the file must be PostScript.
- * Send file directly to printer.
- *
- * Otherwise, send the text-to-postscript leader file '/etc/lpt.ps'
- * followed by the text file.
- *
- * BUGS: must be fed a file, if fed a stream, the first two characters
- * of a non-PostScript stream will be lost.
- */
- void
- text_ps_filter( unused, vparms, unused2 )
- int unused;
- void *vparms;
- void *unused2;
- {
- struct filter_parms *parms;
- int c;
- int *sync, postscript;
- FILE *leader_fp, *original_fp;
- struct filter_stream original_file;
-
- parms = (struct filter_parms *)vparms;
-
- #ifdef LPD_DEBUG
- tprintf( "text_ps_filter( %c )\n", parms->format );
- tflush();
- #endif
-
- postscript = 0;
-
- if( parms->format != 'p' ) {
- /*
- * See if file is encapsulated-postscript
- */
- c = input_char( &parms->input );
- if( c == '%' ) { /* maybe */
- c = input_char( &parms->input );
- if( c == '!' ) /* YES! */
- postscript = 1;
- }
- rewind( parms->input.stream.fp );
- }
-
- YIELD;
- /*
- * save sync address so that text_filter will not signal our
- * parent since output may not be complete.
- */
- sync = parms->sync;
- parms->sync = 0;
-
- if( !postscript ) {
- /*
- * First, the text-to-postscript leader file must be
- * sent to the printer.
- */
- original_file = parms->input; /* save for later */
-
- if( (leader_fp = fopen( "/etc/lpt.ps", "r" )) != NULL ) {
- parms->input.stream.fp = leader_fp;
- parms->input.type = IO_FILE;
- parms->literal = 1;
- /*
- * Now, send the leader through the text_filter.
- */
- text_filter( unused, vparms, unused2 );
- YIELD;
- }
- parms->input = original_file; /* restore */
- }
-
- /*
- * call the standard text_filter. Both file types must now be literal.
- */
- parms->literal = 1;
- text_filter( unused, vparms, unused2 );
- YIELD;
-
- /*
- * signal our parent
- */
- psignal( sync, 0 );
- }
-
-
- /*
- * Format the input file as UNIX pr(1) and send output to socket which
- * should be "piped" to the corresponding IF filter.
- */
- void
- pr_filter( unused, vparms, unused2 )
- int unused;
- void *vparms;
- void *unused2;
- {
- struct pr_parms *parms;
- int line_count, i;
- char buffer[512];
- char page_string[5], *time_string;
- int page_number, text_lines, page_length;
- time_t current_time;
-
- parms = (struct pr_parms *)vparms;
-
- #ifdef LPD_DEBUG
- tputs( "pr_filter()\n" );
- tflush();
- #endif
-
- sockmode( parms->out_s, SOCK_ASCII );
- sockowner( parms->out_s, Curproc ); /* We own it now */
-
- page_number = 1;
- text_lines = parms->length - PR_TOP_MARGIN - PR_BOTTOM_MARGIN;
-
- (void) time( ¤t_time );
- time_string = ctime( ¤t_time );
- rip( time_string );
-
- if( fgets( buffer, 510, parms->file_fp ) == NULL )
- goto EXIT;
-
- for( ;; ) {
- line_count = 1;
-
- for( i = 0; i < PR_TOP_MARGIN/2; i++ )
- usputc( parms->out_s, '\n' );
-
- usputs( parms->out_s, time_string );
- usputs( parms->out_s, " " );
- usputs( parms->out_s, parms->title );
- usputs( parms->out_s, " Page " );
- sprintf( page_string, "%d\n", page_number);
- usputs( parms->out_s, page_string );
-
- for( i = 0; i < PR_TOP_MARGIN/2; i++ )
- usputc( parms->out_s, '\n' );
-
- while( line_count <= text_lines ) {
- line_count++;
- if( *buffer == '\f' ) {
- usputc( parms->out_s, '\n' );
- } else {
- usputs( parms->out_s, buffer );
- if( fgets( buffer, 510, parms->file_fp ) == NULL )
- goto EXIT;
- }
- }
- if( *buffer == '\f' ) {
- if( fgets( buffer, 510, parms->file_fp ) == NULL )
- goto EXIT;
- }
-
- /* bottom margin */
- for( i = 0; i < PR_BOTTOM_MARGIN; i++ )
- usputc( parms->out_s, '\n' );
-
- page_number++;
- }
-
- EXIT: /* finish last page */
-
- usputc( parms->out_s, '\f' );
- close_s( parms->out_s );
- }
-